/* 
 * File:   ThreadAble.cpp
 * Author: bastien
 * 
 * Created on 12 octobre 2010, 11:57
 */

#include "ThreadAble.h"

//test
#include "time.h"

#ifdef USEOF_THREADPOOL
extern  ThreadPool globalThreadPool;
#endif

ThreadAble::ThreadAble() {
    retCode = 0;
    pthread_attr_init(&threadattr);

#ifdef USEOF_THREADPOOL
    globalThreadPool.registerThread(this);
#endif
}

ThreadAble::~ThreadAble() {
    this->cancel();
    pthread_attr_destroy(&threadattr);

#ifdef USEOF_THREADPOOL
    globalThreadPool.unregisterThread(this);
#endif
}

void ThreadAble::run() {
    // thread creation
    int err = pthread_create(&threadid,&threadattr,&ThreadAble::launch_fct,this);
    errorHandle(err);
    //TODO mieux gérer les erreurs
}

void*  ThreadAble::exec(){
   
    std::cout<< "executing thread"<<std::endl;

    std::cout << "exiting thread" << std::endl;

    return 0;
}

void ThreadAble::cancel(){
    if (isRunning()){
        int err = pthread_cancel(threadid);
        errorHandle(err);
    }
}

int ThreadAble::join(){
    void* retCode = 0;

    int err = pthread_join(threadid,&retCode);
    if ( errorHandle(err) == 0 ) return (int)retCode;
    else return err;
}

void ThreadAble::setAsynchronousCancel(){
    int err = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    errorHandle(err);
}

void ThreadAble::setDeferedCancel(){
    int err = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
    errorHandle(err);
}

void ThreadAble::enableCancel(){
    int err = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
    errorHandle(err);
}

void ThreadAble::disableCancel(){
    int err = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    errorHandle(err);
}

void ThreadAble::kill(int sig){
    /*int err = pthread_kill(threadid,sig);
    errorHandle(err);*/
}

bool ThreadAble::isRunning(){
    int err = 0;
    //int err = pthread_kill(threadid,0);
    if (err == 0) return true;
    else return false;
}

void ThreadAble::detach(){
    int err = pthread_detach(threadid);
    errorHandle(err);
}

int ThreadAble::errorHandle(int err){
     switch (err){
        case 0:
        break;

        case EAGAIN: std::cerr << "Insufficient resources to create another thread" <<  std::endl;
        break;

        case EINVAL: std::cerr << "Invalid Value" <<  std::endl;
        break;

        case EPERM: std::cerr << "No permition to do that" <<  std::endl;
        break;

         case EDEADLK: std::cerr << "A deadlock was detected" << std::endl;
        break;

        case ESRCH: std::cerr << "No thread with the ID thread could be found." << std::endl;
        break;

        default:
            std::cerr << "Unknow error" <<  std::endl;
        break;
    }

     return err;
}


void ThreadAble::attrSetDetached(){
    int err = pthread_attr_setdetachstate(&threadattr,PTHREAD_CREATE_DETACHED);
    errorHandle(err);
}

void ThreadAble::attrSetJoinable(){
    int err = pthread_attr_setdetachstate(&threadattr,PTHREAD_CREATE_JOINABLE);
    errorHandle(err);
}

void ThreadAble::yield(){
    sched_yield();
}
